<!doctype html>
<html lang="en-us">

<head>
  <meta charset="utf-8">
  <title>Wasm ImageMagick</title>
  <script DEFER src="https://cdn.jsdelivr.net/g/filesaver.js"></script>
  <script DEFER src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
  <style>
    table,
    th,
    td {
      border: 1px solid black;
      border-collapse: collapse;
    }
  </style>
</head>

<body>
  For license info of this project and related components see <a href="https://github.com/knicknic/WASM-ImageMagick">https://github.com/knicknic/WASM-ImageMagick</a>
  <br><p id="descriptionTxt"></p>
  <div id="advancedOptions" hidden>
    
  
    <table>
      <tr>
        <th>Advanced Options</th>
        <th>Values</th>
      </tr>
      <tr>
        <td>
          <label for="descriptionInput">Description</label>
        </td>
        <td>
            <input type="text" id="descriptionInput" size=120 value="Site lets you execute magick commands in your browser and share commands via url.">
        </td>
      </tr>
      <tr>
        <td>
          <label for="magickCommand">Magick command</label>
        </td>
        <td>
            <input type="text" id="magickCommand" size=120 value="convert * -flatten -crop x20% +repage -quality 100 -scene 0 -set filename:mysize %t %[filename:mysize]-%d.jpeg">
        </td>
      </tr>
      <tr>
        <td>
          <label for="autoZip">Generate Zip when done processing</label>
        </td>
        <td>
          <input type="checkbox" name="autoZip" id="autoZip" value="1">
        </td>
      </tr>
      <tr>
        <td>
          <label for="magickEachPicture">Run command for each picture</label>
        </td>
        <td>
          <input type="checkbox" name="" id="magickEachPicture" value="1" />
        </td>
      </tr>
      <tr>
        <td>
          <label for="showAdvanced">Url shows advanced options</label>
        </td>
        <td>
          <input type="checkbox" name="" id="showAdvanced" value="1" />
        </td>
      </tr>
    </table>
  <p>Share command url: <a id="shareUrl"></a></p>
  <button id="GenerateZip" disabled>Generate Zip of Images</button>
  <br>
  <br>
</div>
<input type=file name=file id="your-files" aria-label="File Input" accept=".jpg,.jpeg,.png,.bmp,.tif,.tiff,.psd" multiple>
<button id="advancedOptionsButton" >Advanced Options</button>
  <div id="Processing" hidden>
    <H2>Processing pictures, ignore unresponsive webpage and wait up to 60 seconds per file, then give up.</H2>
    <H2 id="files-remaining" hidden>0</H2>
  </div>
  <div id="imageHolder" class="image-holder" style="display:flex;flex-direction:column;align-items: flex-start"></div>

  <script type='module'>
    //import the library to talk to imagemagick
    import * as Magick from './magickApi.js';

    // various html elements
    let advancedOptions = document.getElementById('advancedOptions');
    let descriptionTxt = document.getElementById("descriptionTxt");
    let descriptionInput = document.getElementById("descriptionInput");
    let magickCommand = document.getElementById("magickCommand");
    let autoZip = document.getElementById("autoZip");
    let magickEachPicture = document.getElementById("magickEachPicture");
    let showAdvanced = document.getElementById("showAdvanced");
    let shareUrl = document.getElementById("shareUrl");
    let generateZip = document.getElementById("GenerateZip")
    let yourFiles = document.getElementById("your-files");
    let advancedOptionsButton = document.getElementById('advancedOptionsButton');
    let imageHolder = document.getElementById('imageHolder');
    let filesRemaining = document.getElementById("files-remaining");
    let processing = document.getElementById("Processing");

    //service worker
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', function () {
        navigator.serviceWorker.register('sw.js').then(function (registration) {
          let refreshing;
          navigator.serviceWorker.addEventListener('controllerchange',
            function () {
              if (refreshing) return;
              refreshing = true;
              window.location.reload();
            }
          );

          if (registration.active) {
            registration.active.addEventListener('message', function (msg) {
              alert(msg);
              location.reload();
            });
          }
        }, function (err) {
          // registration failed :(
          console.log('ServiceWorker registration failed: ', err);
        });
      });
    }


    // deal with input urls
    {
      let hash = window.location.hash;
      if(hash.length >1)
      {
        try{
          let options = JSON.parse(decodeURIComponent(hash.substring(2)));
          descriptionInput.value = options['desc'];
          magickCommand.value = options['cmd'];
          autoZip.checked = options['autoZip'];
          magickEachPicture.checked = options['magickEachPicture'];
          advancedOptions.hidden = !options['showAdvanced'];
          showAdvanced.checked = options['showAdvanced'];
        }
        catch(e){
          advancedOptions.hidden = false;
        }
      }
      else{
        advancedOptions.hidden = false;
      }
      advancedOptionsButton.onclick = function(){advancedOptions.hidden = !advancedOptions.hidden;};

      let calculateShareUrl = function(){
        let shareUrlObj = {}
        shareUrlObj['desc'] = descriptionInput.value;
        shareUrlObj['cmd'] = magickCommand.value;
        shareUrlObj['autoZip'] = autoZip.checked;
        shareUrlObj['magickEachPicture'] = magickEachPicture.checked;
        shareUrlObj['showAdvanced'] = showAdvanced.checked;
        shareUrl.href=window.location.href.split('#')[0] + "#!" + encodeURIComponent(JSON.stringify(shareUrlObj));
        shareUrl.innerText = shareUrl.href

      }
      magickCommand.oninput = calculateShareUrl;

      descriptionInput.oninput = function(){
        descriptionTxt.innerText = descriptionInput.value;
        calculateShareUrl();
      }
      descriptionInput.oninput();

      autoZip.oninput = calculateShareUrl;
      magickEachPicture.oninput = calculateShareUrl;
      showAdvanced.oninput = calculateShareUrl;

      calculateShareUrl();
    }

    //generate zips
    
    function GenerateZip() {
      let zip = new JSZip();

      if (imageHolder.hasChildNodes()) {
        let children = imageHolder.childNodes;
        for (let i = 0; i < children.length; i++) {
          let child = children[i].wasmResponse;

          zip.file(child['name'], child['blob'])
        }
        zip.generateAsync({ type: "blob" })
          .then(function (content) {
            // see FileSaver.js
            saveAs(content, "out.zip");
          });
      }
    };
    generateZip.onclick = GenerateZip;

    // helper to read user inputed files
    function ReadFile(file){
      let readFile = Magick.CreatePromiseEvent();

      // read fileName & content
      let fr = new FileReader();
      fr.onload = function (txt) {
        let fileName = file.name

        let encoded_txt = txt.target.result;
        let content = new Uint8Array(encoded_txt);
        let sourceFilename = fileName
        
        readFile['resolve']([sourceFilename, content]);
      }
      fr.readAsArrayBuffer(file);

      return readFile;
    };

    let SetProcessing = function (isProcessing){
        //filesRemaining.hidden = !isProcessing;
        processing.hidden = !isProcessing;
    }

    // handle new images to process
    let processFiles = async function () {
      // When the yourFiles has changed, there are new files
      let files = yourFiles.files;

      if (files.length > 0) {
        //clean up old images and show processing screen
        SetProcessing(true);
        imageHolder.innerHTML = '';

        // for each file requested split them (files isn't an array)
        let toProcess=[];
        for (let fileIndex = 0; fileIndex < files.length; ++fileIndex) {
          filesRemaining.innerText = "" + (files.length - fileIndex);
          let [fileName,content] = await ReadFile(files[fileIndex]);
          toProcess.push({'name': fileName, 'content': content})
        }

        let cmd = magickCommand.value;
        let processedFiles = [];

        if(magickEachPicture.checked)
        {
          for (let singleSourceImage of toProcess){
            let newProcessedFiles = await Magick.Call([singleSourceImage], cmd.split(" "));
            processedFiles.push(...newProcessedFiles)
          }
        }
        else
        {          
          processedFiles = await Magick.Call(toProcess, cmd.split(" "));
        }

        for (let file of processedFiles){
          let img = document.createElement('img');
          img.src = URL.createObjectURL(file['blob']);
          img.name = file['name']
          img.wasmResponse = file
          imageHolder.appendChild(img);
        }    
        
        SetProcessing(false);
        if(autoZip.checked)
        {
          GenerateZip();
        }
      }
      generateZip.disabled=!imageHolder.hasChildNodes();
    };
    yourFiles.addEventListener("change", function (event) {
      event.preventDefault();
      processFiles();
    }, false);
  </script>
</body>

</html>